package org.mullin.stratego.shared;

import java.io.Serializable;
import java.util.Date;

import com.googlecode.objectify.annotation.Embed;

@Embed
public class PRank implements Serializable {
    
	public static final double DEFAULT_RATING = 1500;
    public static final double DEFAULT_RD = 350;
    
    // 365 days of not playing to return to DEFAULT_RD
    public static final double c = Math.sqrt((350 * 350 - 50 * 50) / 365);
    public static final double q = Math.log(10) / 400;

    double rating;
    double ratingDeviation;

    public PRank() {
            rating = DEFAULT_RATING;
            ratingDeviation = DEFAULT_RD;
    }

    public void updateRatingDeviation(Date dateOfLastGame) {
            Date now = new Date();
            long dayPassed = millisecondsToDays(now.getTime()
                            - dateOfLastGame.getTime());
            ratingDeviation = Math.min(Math.sqrt(ratingDeviation * ratingDeviation + c * c * dayPassed), 350);
    }

    private long millisecondsToDays(long l) {
            return (long) ((double) l / 1000 / 60 / 60 / 24);
    }

    public void updateAfterGame(double RDj, double rj, double sj) {
            double dSquare = dSquare(RDj, rj);
            rating = rating + q / (1 / (ratingDeviation * ratingDeviation) + 1 / dSquare) * g(RDj) * (sj - E(RDj, rj));
            ratingDeviation = Math.sqrt(1 / (1 / (ratingDeviation * ratingDeviation) + 1 / dSquare));
    }

    private double dSquare(double RDj, double rj) {
            return 1 / (q * q * g(RDj) * g(RDj) * E(RDj, rj) * (1 - E(RDj, rj)));
    }

    private double g(double RD) {
            return 1 / Math.sqrt(1 + 3 * q * q * RD * RD / Math.PI / Math.PI);
    }

    private double E(double RDj, double rj) {
            return 1 / (1 + Math.pow(10, -g(RDj) * (rating - rj) / 400));
    }

    public double getRatingDeviation() {
            return ratingDeviation;
    }

    public double getRating() {
            return rating;
    }

    @Override
    public String toString() {
//            return String.format("[%d, %d]", (long) (rating - 2 * ratingDeviation),
//                            (long) (rating + 2 * ratingDeviation));
    	return "";
    }
}
